package com.gitee.wsl.struct.command.parameters.types


import com.gitee.wsl.shouldThrow
import com.gitee.wsl.struct.command.internal.BadParameterValue
import com.gitee.wsl.struct.command.internal.NoSuchOption
import com.gitee.wsl.struct.command.model.parameters.arguments.argument
import com.gitee.wsl.struct.command.model.parameters.options.delegate.option
import com.gitee.wsl.struct.command.model.parameters.options.tran.default
import com.gitee.wsl.struct.command.model.parameters.types.uint
import com.gitee.wsl.struct.command.testing.TestCommand
import com.gitee.wsl.struct.command.testing.formattedMessage
import com.gitee.wsl.struct.command.testing.parse
import com.gitee.wsl.test.forAll
import com.gitee.wsl.test.row
import com.gitee.wsl.test.shouldBe
import kotlin.js.JsName
import kotlin.test.Test

class UIntTest {
    @Test
    @JsName("uint_option")
    fun `uint option`() = forAll(
        row("", null),
        row("-x0", 0u),
        row("-${UInt.MAX_VALUE}", UInt.MAX_VALUE),
    ) { argv, expected ->
        class C : TestCommand() {
            val x: UInt? by option("-x").uint(acceptsValueWithoutName = true)
            override fun run_() {
                x shouldBe expected
            }
        }

        C().parse(argv)
    }

    @Test
    @JsName("uint_option_with_default")
    fun `uint option with default`() = forAll(
        row("", 111u),
        row("--xx=4", 4u),
        row("-x5", 5u)
    ) { argv, expected ->
        class C : TestCommand() {
            val x: UInt by option("-x", "--xx").uint().default(111u)
            override fun run_() {
                x shouldBe expected
            }
        }
        C().parse(argv)
    }

    @Test
    @JsName("uint_option_error")
    fun `uint option error`() {
        class C : TestCommand(called = false) {
            @Suppress("unused")
            val foo by option().uint()
        }

        shouldThrow<BadParameterValue> { C().parse("--foo bar") }
            .formattedMessage shouldBe "invalid value for --foo: bar is not a valid integer"

        shouldThrow<NoSuchOption> { C().parse("-2") }
        shouldThrow<BadParameterValue> { C().parse("--foo=-1") }
    }

    @Test
    @JsName("uint_argument")
    fun `uint argument`() {
        class C : TestCommand(treatUnknownOptionsAsArgs = true) {
            val a by argument().uint()
        }

        C().parse("2").a shouldBe 2u
        shouldThrow<BadParameterValue> { C().parse("-1") }
    }
}
